package cn.kimming.rpc.remoting.server;

import cn.kimming.rpc.common.exception.RpcException;
import cn.kimming.rpc.common.util.ClassUtil;
import cn.kimming.rpc.remoting.registry.ServerRpcRegistry;
import cn.kimming.rpc.remoting.registry.UpdateServiceCallCountTask;
import cn.kimming.rpc.remoting.transport.RpcRequest;
import cn.kimming.rpc.remoting.transport.RpcResponse;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 服务调用任务(在业务线程池中完成)
 */
public class ServiceCallTask implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(ServiceCallTask.class);
    private RpcRequest request;
    private Channel channel;
    private ServiceMap serviceMap;

    public ServiceCallTask(RpcRequest request, ServiceMap serviceMap, Channel channel) {
        this.request = request;
        this.serviceMap = serviceMap;
        this.channel = channel;
    }

    @Override
    public void run() {
        logger.info("request: {} is executed by thread: {}", request.getRequestId(), Thread.currentThread().getName());

        RpcResponse response = new RpcResponse();
        response.setSuccess(false);
        // 绑定requestId
        response.setRequestId(request.getRequestId());

        String interfaceName = null;
        Method method = null;
        try {
            // 加载接口
            interfaceName = request.getInterfaceName();
            Class<?> interfaceClz = Class.forName(interfaceName);
            // 获取服务实现
            Object serviceRef = serviceMap.get(interfaceName);

            // 获取调用方法
            String methodName = request.getMethodName();
            String[] methodTypeNames = request.getMethodTypeNames();
            Class[] methodTypes = ClassUtil.parseNames2Classes(methodTypeNames);
            method = interfaceClz.getDeclaredMethod(methodName, methodTypes);

            // 调用实现类方法
            Object[] methodArgs = request.getMethodArgs();
            Object result = method.invoke(serviceRef, methodArgs);
            response.setSuccess(true);
            response.setResult(result);
            logger.info("request: {}'s response: {}", request.getRequestId(), response.toString());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            response.setError(new RpcException("服务列表中没有此服务: " + interfaceName));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            response.setError(new RpcException("服务接口中没有此方法: " + method.getName()));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            response.setError(new RpcException("服务端业务方法出错"));
        }

        channel.writeAndFlush(response).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);

        // 更新服务调用次数, 调用zk专用线程池, 不阻塞当前线程
        ServerRpcRegistry.getRegistryThreadPool().submit(new UpdateServiceCallCountTask(interfaceName));

    }

}
